package com.linsen.erp.admin.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linsen.erp.admin.provider.enums.DataScopeCustomizeTypeEnum;
import com.linsen.erp.admin.provider.enums.DataScopeTypeEnum;
import com.linsen.erp.admin.provider.vo.*;
import com.linsen.core.common.exception.BaseException;
import com.linsen.erp.admin.entity.*;
import com.linsen.erp.admin.service.*;
import com.linsen.erp.admin.mapper.RoleMapper;
import com.linsen.erp.admin.provider.dto.RoleDTO;
import com.linsen.erp.admin.provider.qo.RoleQo;
import com.linsen.core.common.enums.DeleteType;
import com.linsen.core.common.enums.YnType;
import com.linsen.core.common.util.ConvertUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色表 服务实现类
 * </p>
 *
 * @author zhaoyong
 * @since 2023-07-24
 */
@Service
@RequiredArgsConstructor
public class RoleServiceImpl extends ServiceImpl<RoleMapper, RoleEntity> implements IRoleService {

    private final IRoleMenuService iRoleMenuService;
    private final IMenuService iMenuService;
    private final IRoleDataScopeService iRoleDataScopeService;
    private IDeptService iDeptService;
    @Autowired
    public void setiDeptService(IDeptService iDeptService) {
        this.iDeptService = iDeptService;
    }
    private IUserService iUserService;
    @Autowired
    public void setiUserService(IUserService iUserService) {
        this.iUserService = iUserService;
    }

    @Override
    public List<String> getCodeByUserid(String userid,Integer isAdmin) {
        if (ObjectUtil.equal(isAdmin, YnType.YES.getValue())){
            //默认获取全部角色code
             return this.list(
                    new LambdaQueryWrapper<RoleEntity>()
                            .eq(RoleEntity::getIsDeleted, DeleteType.NORMAL.getValue())
            ).stream().map(RoleEntity::getCode).collect(Collectors.toList());
        }

        return this.getBaseMapper().getCodeByUserid(userid);
    }

    /** 封装分页列表查询的wrapper对象 */
    private Wrapper<RoleEntity> getWrapper(RoleQo roleQo){
        String name = roleQo.getName();
        Integer permissionType = roleQo.getPermissionType();

        return new LambdaQueryWrapper<RoleEntity>()
                .like(ObjectUtil.isNotEmpty(name),RoleEntity::getName,name)
                .eq(ObjectUtil.isNotNull(permissionType),RoleEntity::getPermissionType,permissionType)
                .eq(RoleEntity::getIsDeleted,DeleteType.NORMAL.getValue())
                .orderByAsc(RoleEntity::getPriority)
                .orderByDesc(RoleEntity::getCreateTime);
    }

    @Override
    public Page<RoleVO> page(RoleQo qo) {
        Page<RoleEntity> page = this.page(new Page<>(qo.getCurrent(), qo.getSize()), getWrapper(qo));

        Page<RoleVO> roleVOPage = new Page<>(qo.getCurrent(), qo.getSize());
        roleVOPage.setTotal(page.getTotal());

        //获取全部菜单列表信息
        Map<String, MenuVO> menuVOMap = ConvertUtil.convert(
                iMenuService.list(
                        new LambdaQueryWrapper<MenuEntity>()
                                .eq(MenuEntity::getIsDeleted, DeleteType.NORMAL.getValue())
        ),MenuVO.class).stream().collect(Collectors.toMap(MenuVO::getId, Function.identity(), (key1, key2) -> key2));

        //为了减少查询性能开销，只有分页列表存在数据权限范围为"自定义范围"时再查询加载
        Map<String, DeptVO> deptVOMap = null;
        Map<String, UserVO> userVOMap = null;

        List<RoleVO> roleVOList = new ArrayList<>();
        for (RoleEntity roleEntity : page.getRecords()) {
            RoleVO roleVO = ConvertUtil.convert(roleEntity, RoleVO.class);
            String roleId = roleVO.getId();

            List<String> menuIdList = iRoleMenuService.getMenuIdByRoleId(roleId);
            List<MenuVO> menuVOList = new ArrayList<>();
            menuIdList = menuIdList.stream().filter(menuId -> {
                MenuVO menuVO = menuVOMap.get(menuId);
                if (ObjectUtil.isNull(menuVO)){
                    return false;
                }
                menuVOList.add(menuVO);
                return true;
            }).collect(Collectors.toList());
            roleVO.setMenuIdList(menuIdList);
            roleVO.setMenuVOList(menuVOList);

            Integer permissionType = roleVO.getPermissionType();
            if (ObjectUtil.equal(permissionType, DataScopeTypeEnum.CUSTOMIZE.getValue())) {
                //数据权限自定义范围id列表-部门
                List<String> roleDataScopeDeptIdList = new ArrayList<>();
                //数据权限自定义范围详情列表-部门
                List<DeptVO> roleDataScopeDeptVOList = new ArrayList<>();
                //数据权限自定义范围id列表-用户
                List<String> roleDataScopeUserIdList = new ArrayList<>();
                //数据权限自定义范围详情列表-用户
                List<UserVO> roleDataScopeUserVOLis = new ArrayList<>();

                List<RoleDataScopeEntity> roleDataScopeEntityList = iRoleDataScopeService.getByRoleId(roleId);
                for (RoleDataScopeEntity roleDataScopeEntity : roleDataScopeEntityList) {
                    Integer type = roleDataScopeEntity.getType();
                    String dataId = roleDataScopeEntity.getDataId();
                    if (ObjectUtil.equal(type, DataScopeCustomizeTypeEnum.DEPT.getValue())) {
                        if (ObjectUtil.isNull(deptVOMap)) {
                            //获取全部部门列表信息
                            deptVOMap = ConvertUtil.convert(
                                    iDeptService.list(
                                            new LambdaQueryWrapper<DeptEntity>()
                                                    .eq(DeptEntity::getIsDeleted, DeleteType.NORMAL.getValue())
                                    ), DeptVO.class).stream().collect(Collectors.toMap(DeptVO::getId, Function.identity(), (key1, key2) -> key2));
                        }
                        Optional.ofNullable(deptVOMap.get(dataId)).ifPresent(deptVO -> {
                            roleDataScopeDeptVOList.add(deptVO);
                            roleDataScopeDeptIdList.add(dataId);
                        });
                    }else if (ObjectUtil.equal(type, DataScopeCustomizeTypeEnum.USER.getValue())) {
                        if (ObjectUtil.isNull(userVOMap)) {
                            //获取全部用户信息
                            userVOMap = ConvertUtil.convert(
                                    iUserService.list(
                                            new LambdaQueryWrapper<UserEntity>()
                                                    .eq(UserEntity::getIsDeleted, DeleteType.NORMAL.getValue())
                                    ), UserVO.class).stream().collect(Collectors.toMap(UserVO::getId, Function.identity(), (key1, key2) -> key2));
                        }
                        Optional.ofNullable(userVOMap.get(dataId)).ifPresent(userVO -> {
                            roleDataScopeUserVOLis.add(userVO);
                            roleDataScopeUserIdList.add(dataId);
                        });
                    }
                }

                roleVO.setRoleDataScopeDeptIdList(roleDataScopeDeptIdList);
                roleVO.setRoleDataScopeDeptVOList(roleDataScopeDeptVOList);
                roleVO.setRoleDataScopeUserIdList(roleDataScopeUserIdList);
                roleVO.setRoleDataScopeUserVOList(roleDataScopeUserVOLis);
            }

            roleVOList.add(roleVO);
        }
        roleVOPage.setRecords(roleVOList);

        return roleVOPage;
    }

    @Override
    public RoleVO get(String id) {
        RoleEntity roleEntity = this.getById(id);
        RoleVO roleVO = ConvertUtil.convert(roleEntity, RoleVO.class);

        List<String> menuIdList = iRoleMenuService.getMenuIdByRoleId(id);
        if (ObjectUtil.isNotEmpty(menuIdList)){
            List<MenuEntity> menuEntityList = iMenuService.list(
                    new LambdaQueryWrapper<MenuEntity>()
                            .in(MenuEntity::getId, menuIdList)
                            .eq(MenuEntity::getIsDeleted, DeleteType.NORMAL.getValue())
            );
            if (ObjectUtil.isNotEmpty(menuEntityList)){
                roleVO.setMenuVOList(ConvertUtil.convert(menuEntityList,MenuVO.class));
                roleVO.setMenuIdList(menuEntityList.stream().map(MenuEntity::getId).collect(Collectors.toList()));
            }
        }

        Integer permissionType = roleVO.getPermissionType();
        if (ObjectUtil.equal(permissionType, DataScopeTypeEnum.CUSTOMIZE.getValue())) {
            //数据权限自定义范围id列表-部门
            List<String> roleDataScopeDeptIdList = new ArrayList<>();
            //数据权限自定义范围id列表-用户
            List<String> roleDataScopeUserIdList = new ArrayList<>();

            List<RoleDataScopeEntity> roleDataScopeEntityList = iRoleDataScopeService.getByRoleId(id);
            for (RoleDataScopeEntity roleDataScopeEntity : roleDataScopeEntityList) {
                Integer type = roleDataScopeEntity.getType();
                String dataId = roleDataScopeEntity.getDataId();
                if (ObjectUtil.equal(type, DataScopeCustomizeTypeEnum.DEPT.getValue())) {
                    roleDataScopeDeptIdList.add(dataId);
                }else if (ObjectUtil.equal(type, DataScopeCustomizeTypeEnum.USER.getValue())) {
                    roleDataScopeUserIdList.add(dataId);
                }
            }
            if (ObjectUtil.isNotEmpty(roleDataScopeDeptIdList)){
                List<DeptEntity> deptEntityList = iDeptService.list(
                        new LambdaQueryWrapper<DeptEntity>()
                                .in(DeptEntity::getId, roleDataScopeDeptIdList)
                                .eq(DeptEntity::getIsDeleted, DeleteType.NORMAL.getValue())
                );
                if (ObjectUtil.isNotEmpty(deptEntityList)){
                    roleVO.setRoleDataScopeDeptVOList(ConvertUtil.convert(deptEntityList,DeptVO.class));
                    roleVO.setRoleDataScopeDeptIdList(deptEntityList.stream().map(DeptEntity::getId).collect(Collectors.toList()));
                }
            }
            if (ObjectUtil.isNotEmpty(roleDataScopeUserIdList)){
                List<UserEntity> userEntityList = iUserService.list(
                        new LambdaQueryWrapper<UserEntity>()
                                .in(UserEntity::getId, roleDataScopeUserIdList)
                                .eq(UserEntity::getIsDeleted, DeleteType.NORMAL.getValue())
                );
                if (ObjectUtil.isNotEmpty(userEntityList)){
                    roleVO.setRoleDataScopeUserVOList(ConvertUtil.convert(userEntityList,UserVO.class));
                    roleVO.setRoleDataScopeUserIdList(userEntityList.stream().map(UserEntity::getId).collect(Collectors.toList()));
                }
            }
        }

        return roleVO;
    }

    private void checkRole(RoleDTO roleDTO){
        Integer permissionType = roleDTO.getPermissionType();
        if (ObjectUtil.isNull(permissionType)){
            throw new BaseException("必须选择角色对应数据权限类型");
        }
        if (ObjectUtil.equal(permissionType,DataScopeTypeEnum.CUSTOMIZE.getValue())){
            List<String> roleDataScopeDeptIdList = roleDTO.getRoleDataScopeDeptIdList();
            List<String> roleDataScopeUserIdList = roleDTO.getRoleDataScopeUserIdList();
            if (ObjectUtil.isEmpty(roleDataScopeDeptIdList) &&
                    ObjectUtil.isEmpty(roleDataScopeUserIdList)){
                throw new BaseException("数据权限自定义范围时必须勾选至少一个选项");
            }
        }
    }

    @Transactional
    @Override
    public void saveRole(RoleDTO roleDTO) {
        checkRole(roleDTO);

        RoleEntity roleEntity = ConvertUtil.convert(roleDTO, RoleEntity.class);
        this.save(roleEntity);
        String roleId = roleEntity.getId();

        List<String> menuIdList = roleDTO.getMenuIdList();
        iRoleMenuService.set(roleId,menuIdList);

        List<String> roleDataScopeDeptIdList = roleDTO.getRoleDataScopeDeptIdList();
        List<String> roleDataScopeUserIdList = roleDTO.getRoleDataScopeUserIdList();
        iRoleDataScopeService.set(roleId,roleDataScopeDeptIdList,roleDataScopeUserIdList);
    }

    @Transactional
    @Override
    public void updateRole(RoleDTO roleDTO) {
        checkRole(roleDTO);

        RoleEntity roleEntity = ConvertUtil.convert(roleDTO, RoleEntity.class);
        this.updateById(roleEntity);
        String roleId = roleEntity.getId();

        List<String> menuIdList = roleDTO.getMenuIdList();
        iRoleMenuService.set(roleId,menuIdList);

        List<String> roleDataScopeDeptIdList = roleDTO.getRoleDataScopeDeptIdList();
        List<String> roleDataScopeUserIdList = roleDTO.getRoleDataScopeUserIdList();
        iRoleDataScopeService.set(roleId,roleDataScopeDeptIdList,roleDataScopeUserIdList);
    }

    @Transactional
    @Override
    public void delete(String id) {
        this.update(
                new UpdateWrapper<RoleEntity>().lambda()
                        .set(RoleEntity::getIsDeleted,DeleteType.DELETED.getValue())
                        .eq(RoleEntity::getId,id)
        );
    }

    @Override
    public void setSystemUserVO(SystemUserVO systemUserVO, UserEntity userEntity) {
        String userid = userEntity.getId();
        Integer isAdmin = userEntity.getIsAdmin();
        String deptId = userEntity.getDeptId();

        if (ObjectUtil.equal(isAdmin, YnType.YES.getValue())){
            systemUserVO.setPermissionType(YnType.YES.getValue());
            return;
        }

        List<RoleEntity> roleEntityList = this.getBaseMapper().getByUserid(userid);

        boolean hasAll = false;
        boolean hasDept = false;
        boolean hasDeptFetch = false;
        List<RoleEntity> customizeList = new ArrayList<>();
        for (RoleEntity roleEntity : roleEntityList) {
            if (ObjectUtil.equal(roleEntity.getPermissionType(), DataScopeTypeEnum.ALL.getValue())) {
                hasAll = true;
            }else if (ObjectUtil.equal(roleEntity.getPermissionType(), DataScopeTypeEnum.DEPT.getValue())) {
                hasDept = true;
            }else if (ObjectUtil.equal(roleEntity.getPermissionType(), DataScopeTypeEnum.DEPT_FETCH.getValue())) {
                hasDeptFetch = true;
            }else if (ObjectUtil.equal(roleEntity.getPermissionType(), DataScopeTypeEnum.CUSTOMIZE.getValue())) {
                customizeList.add(roleEntity);
            }
        }

        if (hasAll) {
            systemUserVO.setPermissionType(YnType.YES.getValue());
            return;
        }

        Set<String> deptIdSet = new HashSet<>();
        Set<String> userIdSet = CollectionUtil.newHashSet(userid);//默认包含自己

        if (hasDeptFetch) {
            deptIdSet.addAll(iDeptService.getSubDeptidList(deptId));
        }else if (hasDept) {
            deptIdSet.add(deptId);
        }

        for (RoleEntity roleEntity : customizeList) {
            String roleId = roleEntity.getId();

            List<RoleDataScopeEntity> roleDataScopeEntityList = iRoleDataScopeService.getByRoleId(roleId);
            roleDataScopeEntityList.forEach(roleDataScopeEntity -> {
                Integer type = roleDataScopeEntity.getType();
                String dataId = roleDataScopeEntity.getDataId();
                if (ObjectUtil.equal(type, DataScopeCustomizeTypeEnum.DEPT.getValue())) {
                    deptIdSet.add(dataId);
                }else if (ObjectUtil.equal(type, DataScopeCustomizeTypeEnum.USER.getValue())) {
                    userIdSet.add(dataId);
                }
            });
        }

        systemUserVO.setPermissionType(YnType.NO.getValue());
        systemUserVO.setRoleDataScopeDeptIdList(CollectionUtil.newArrayList(deptIdSet));
        systemUserVO.setRoleDataScopeUserIdList(CollectionUtil.newArrayList(userIdSet));
    }
}
